package com.example.chatroom.api;

import com.example.chatroom.component.OnlineUserManager;
import com.example.chatroom.mapper.MessageMapper;
import com.example.chatroom.mapper.MessageSessionMapper;
import com.example.chatroom.model.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.List;

@Component
public class WebSocketAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private MessageSessionMapper messageSessionMapper;
    @Autowired
    private OnlineUserManager onlineUserManager;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("[WebSocketAPI] 连接成功!");
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        // 把这个键值对存起来
        onlineUserManager.online(user.getUserId(), session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("[WebSocketAPI] 收到消息!" + message.toString());
        // 1. 先获取到当前用户的信息
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            System.out.println("[WebSocketAPI] user == null! 未登录用户， 无法进行消息转发");
        }
        // 2. 针对请求进行解析，把 json 格式的字符串， 转成一个 Java 对象
        MessageRequest req = objectMapper.readValue(message.getPayload(), MessageRequest.class);
        if (req.getType().equals("message")) {
            // 就进行消息转发
            transferMessage(user, req);
        } else {
            System.out.println("[WebSocketAPI] req.type 有误！" + message.getPayload());
        }
    }

    /**
     * 通过这个方法来完成消息实际转发的工作.
     * @param fromUser 表示这个要转发的消息, 是从谁那来的
     * @param req
     */
    @lombok.SneakyThrows
    private void transferMessage(User fromUser, MessageRequest req) {
        // 1. 先准备一个带转发的响应对象. MessageResponse
        MessageResponse resp = new MessageResponse();
        resp.setType("message");
        resp.setFromId(fromUser.getUserId());
        resp.setFromName(fromUser.getUsername());
        resp.setSessionId(req.getSessionId());
        resp.setContent(req.getContent());
        // 把这个 java 对象转成 json 格式字符串
        String respJson = objectMapper.writeValueAsString(resp);
        System.out.println("[transferMessage] respJson: " + respJson);

        // 2. 根据请求中的 sessionId, 获取到这个 MessageSession 里都有哪些用户, 通过查询数据库就能够知道了
        List<Friend> friends = messageSessionMapper.getFriendBySessionId(req.getSessionId(), fromUser.getUserId());
        // 把当前用户也添加到上述的 List 中
        Friend myself = new Friend();
        myself.setFriendId(fromUser.getUserId());
        myself.setFriendName(fromUser.getUsername());
        friends.add(myself);

        // 3. 循环遍历上述的这个列表, 给列表中的每个用户都发一分响应消息
        //  注意: 这里除了给查询到的好友发, 也要给自己发一个, 方便实现在自己客户端上显示自己发送的消息
        for (Friend friend : friends) {
            WebSocketSession webSocketSession = onlineUserManager.getSession(friend.getFriendId());
            if (webSocketSession == null) {
                // 如果用户未在线, 则不发送
                continue;
            }
            webSocketSession.sendMessage(new TextMessage(respJson));
        }

        // 4. 转发的消息, 还需要放进数据库中, 后续用户下线之后, 重新上线, 还可以通过历史消息拿到之前的消息.
        Message message = new Message();
        message.setFromId(fromUser.getUserId());
        message.setSessionId(req.getSessionId());
        message.setContent(req.getContent());

        messageMapper.add(message);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("[WebSocketAPI] 连接关闭!" + status.toString());

        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        onlineUserManager.offline(user.getUserId(), session);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("[WebSocketAPI] 连接异常!" + exception.toString());

        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        onlineUserManager.offline(user.getUserId(), session);
    }
}
